﻿using System;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using AvalonDock;
using Foundation;
using Poet.Views;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;

namespace Poet.ViewModels
{
    /// <summary>
    /// Main view model.
    /// </summary>
    public class MainViewModel : BaseMainViewModel
    {
        private readonly OpenFileDialog _openFileDialog = new OpenFileDialog();

        public MainViewModel()
        {   
            Topmost = false;
            ShowInTray = true;
            ShowMainMenu = true;
            ShowInTaskbar = true;
            ShowStatusBar = true;
            ShowStandartToolBar = true;
            DisableWindowActivation = false;
            ResizeMode = ResizeMode.CanResizeWithGrip;

            DocumentViews = new ObservableCollection<DocumentView>();
            ToolViews = new ObservableCollection<ManagedContent>();

            New = ApplicationCommands.New;
            Open = ApplicationCommands.Open;
            Exit = new Command(o => Environment.Exit(0));
            About = new Command(o => new AboutView { DataContext = new AboutViewModel() }.ShowDialog());
            SaveAll = new RoutedCommand(PropertyNameProvider.GetPropertyName(() => SaveAll), GetType());
            CloseAll = new RoutedCommand(PropertyNameProvider.GetPropertyName(() => CloseAll), GetType());

            ApplicationCommands.Save.CanExecuteChanged += (sender, args) => ((Command)SaveAll).NotifyWhenCanExecuteChanged();
            ApplicationCommands.Close.CanExecuteChanged += (sender, args) => ((Command)CloseAll).NotifyWhenCanExecuteChanged();

            CommandBindings.Add(new CommandBinding(CloseAll, CloseAllExecuted, CloseAllCanExecute));
            CommandBindings.Add(new CommandBinding(SaveAll, SaveAllExecuted, SaveAllCanExecute));
            CommandBindings.Add(new CommandBinding(New, (o, e) => CreateNewDocument()));
            CommandBindings.Add(new CommandBinding(Open, OpenExecuted));

            var lastWindowState = WindowState;
            PropertyChanged += (sender, args) =>
                                   {
                                       if (WindowState != WindowState.Minimized &&
                                           args.PropertyName == PropertyNameProvider.GetPropertyName(() => WindowState))
                                           lastWindowState = WindowState;
                                   };

            InstanceManager.OnReciveArguments += fileNames =>
                                                     {
                                                         if (!fileNames.Any())
                                                         {
                                                             Application.Current.Dispatcher.BeginInvoke(
                                                                 DispatcherPriority.Normal,
                                                                 new ThreadStart(
                                                                     () =>
                                                                         {
                                                                             if (WindowState == WindowState.Minimized)
                                                                                 Application.Current.MainWindow.
                                                                                     WindowState = lastWindowState;
                                                                             Application.Current.MainWindow.Activate();
                                                                         }));
                                                         }

                                                         foreach (var fileName in fileNames)
                                                         {
                                                             Application.Current.Dispatcher.BeginInvoke(
                                                                 DispatcherPriority.Normal,
                                                                 (ParameterizedThreadStart) OpenFile, fileName);
                                                         }
                                                     };
        }

        public ICommand SaveAll { get; set; }

        public ICommand CloseAll { get; set; }

        public ObservableCollection<DocumentView> DocumentViews { get; private set; }
        
        public ObservableCollection<ManagedContent> ToolViews { get; private set; }

        public object ActiveContent
        {
            get { return Get(() => ActiveContent); }
            set { Set(() => ActiveContent, value); }
        }

        public object ActiveDocument
        {
            get { return Get(() => ActiveDocument); }
            set { Set(() => ActiveDocument, value); }
        }

        public bool Topmost
        {
            get { return Get(() => Topmost); }
            set { Set(() => Topmost, value); }
        }

        public bool ShowInTray
        {
            get { return Get(() => ShowInTray); }
            set { Set(() => ShowInTray, value); }
        }

        public bool ShowInTaskbar
        {
            get { return Get(() => ShowInTaskbar); }
            set { Set(() => ShowInTaskbar, value); }
        }

        public bool DisableWindowActivation
        {
            get { return Get(() => DisableWindowActivation); }
            set { Set(() => DisableWindowActivation, value); }
        }

        public WindowStyle WindowStyle
        {
            get { return Get(() => WindowStyle); }
            set { Set(() => WindowStyle, value); }
        }

        public WindowState WindowState
        {
            get { return Get(() => WindowState); }
            set { Set(() => WindowState, value); }
        }

        public ResizeMode ResizeMode
        {
            get { return Get(() => ResizeMode); }
            set { Set(() => ResizeMode, value); }
        }

        public Icon TrayIcon
        {
            get { return Properties.Resources.Rose; }
        }

        public void OpenFile(object fileName)
        {
            lock (DocumentViews)
            {
                var viewModel = new DocumentViewModel((string) fileName);
                var view = new DocumentView();
                viewModel.Bind(view);
                DocumentViews.Add(view);
            }
        }

        private void OpenExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
        {
            if (_openFileDialog.ShowDialog() != true)
            {
                return;
            }

            try
            {
                foreach (var fileStream in _openFileDialog.OpenFiles())
                {
                    var documentViewModel = CreateNewDocument();
                    documentViewModel.Load(fileStream);
                }

                DocumentViews.Last().Activate();
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
        }

        private void SaveAllCanExecute(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
        {
            canExecuteRoutedEventArgs.CanExecute = DocumentViews.Any(v => ApplicationCommands.Save.CanExecute(null, v));
        }

        private void SaveAllExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
        {
            foreach (var documentView in DocumentViews.Where(v => ApplicationCommands.Save.CanExecute(null, v)))
            {
                ApplicationCommands.Save.Execute(null, documentView);
            }
        }

        private void CloseAllCanExecute(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
        {
            canExecuteRoutedEventArgs.CanExecute = DocumentViews.Any(v => ApplicationCommands.Close.CanExecute(null, v));
        }

        private void CloseAllExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
        {
            foreach (
                var documentView in DocumentViews.Where(v => ApplicationCommands.Close.CanExecute(null, v)).ToList())
            {
                ApplicationCommands.Close.Execute(null, documentView);
            }
        }

        private DocumentViewModel CreateNewDocument()
        {
            var view = new DocumentView();
            var viewModel = new DocumentViewModel();
            viewModel.Bind(view);
            viewModel.OnClosed += (o, e) => view.Close();
            DocumentViews.Add(view);
            return viewModel;
        }
    }
}
